﻿#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "crc32.h"
#include "stdint.h"

#define VERSION_SZ          24
#pragma pack(1)
typedef struct {
    uint16_t magic;             //固定为0xAEAE
    uint8_t  encrypt_algo;
    uint8_t  resv[1];
    uint8_t  version[VERSION_SZ]; //文件版本号描述
    uint32_t crc32;               //文件crc校验
    uint32_t size;                //文件长度
}firmware_info_t;
#pragma pack()

int execmd(char* cmd, char* result) {
    char buffer[128];                         //定义缓冲区                        
    FILE* pipe = _popen(cmd, "r");            //打开管道，并执行命令 
    if (!pipe)
        return 0;                      //返回0表示运行失败 

    while (!feof(pipe)) {
        if (fgets(buffer, 128, pipe)) {             //将管道输出到result中 
            strcat(result, buffer);
        }
    }
    //printf("res:%s",result);
    _pclose(pipe);                            //关闭管道 
    return 1;                                 //返回1表示运行成功 
}
/*
int main(){
char result[1024*4]="";                   //定义存放结果的字符串数组
if(1==execmd("ipconfig",result)){
printf(result);
    }
system("pause");                          //暂停以查看结果
} */

int query_argv(char* str, int argc, char* argv[])
{
    int i = 0;
    for (i = 1; i < argc; i++)
    {
        if (strcmp(argv[i], str) == 0)
            break;
    }
    if (i == argc)
        return 0;
    else
        return i;
}

int main(int argc, char* argv[])
{
    time_t timep;
    struct tm* p;
    FILE* fp = NULL;
    FILE* fp1 = NULL;
    FILE* f_boot = NULL;
    firmware_info_t fw_info;
    unsigned int crc = 0;
    unsigned char c;
    char dest_file_name[128] = "";
    char src_file_name[128] = "";
    int offset;
    char ver[1024] = "";
    int n;
    int opt = 0;
    int opt_fix_time = 0;
    char* pt;

    printf("argc=%d\n", argc);

    n = query_argv((char*)"-p", argc, argv);
    if (n != 0 && n + 1 < argc)
    {
        sprintf(dest_file_name, "%s", argv[n + 1]);
        if (dest_file_name[strlen(dest_file_name) - 1] != '\\')
            strcat(dest_file_name, "\\");
    }
    n = query_argv((char *)"-i", argc, argv);
    if (n != 0 && n + 1 < argc)
    {
        opt = 1;
        strcpy(src_file_name, argv[n + 1]);
        pt = strrchr(argv[n + 1], '\\');
        if (pt == NULL)
            pt = strrchr(argv[n + 1], '/');
        sprintf(dest_file_name + strlen(dest_file_name), "%s", pt == NULL ? argv[n + 1] : pt + 1);
        pt = strstr(dest_file_name, ".bin");
        if (pt != NULL)
            *pt = '\0';
    }
    else
    {
        opt = 0;
    }
    //printf("src_file_name:%s\n",src_file_name);
    printf("opt=%d\n", opt);
    n = query_argv((char*)"-t", argc, argv);
    if (n != 0)
        opt_fix_time = 1;

    int res = 0;
    if (0 == execmd((char *)"svnversion", ver))
        res = -1;

    if (strlen(ver) == 0)
        res = -1;

    if (strstr(ver, "Unversioned directory"))
        res = -1;
    if (res == -1)
    {
        sprintf(ver, "0");//svnversion is invalid
    }

    char* xoffset;
    if ((xoffset = strchr(ver, ':')) != NULL)
        *xoffset = '_';
    xoffset = strchr(ver, '\n');
    if (xoffset != 0)
        *xoffset = '\0';
    printf("svn revision:%s %d", ver, atoi(ver));
    //system("svnversion");

    if (opt == 0)
    {
        char cfile[128];
        char _version_[4096];
        char flag = 1;

        n = query_argv((char*)"-o", argc, argv);
        if (n != 0 && n + 1 < argc)
            strcpy(cfile, argv[n + 1]);
        else
            strcpy(cfile, "_svn_version_.c");

        fp = fopen(cfile, "rb");
        if (fp != NULL)
        {
            pt = _version_;
            while (1)
            {
                c = fgetc(fp);
                if (feof(fp))
                {
                    break;
                }
                printf("%c", c);
                *pt++ = c;
            }
            fclose(fp);
            printf("\nsvnversion:%s len:%d\n", ver, strlen(ver));
            pt = strstr(_version_, "return \"");
            pt = strstr(pt, ver);
            if (NULL != pt) {
                if (*(pt - 1) == '\"') {
                    printf("\nversion is not update\n");
                    flag = 0;
                }
            }
            else
            {
                printf("\nversion is update\n");

            }
        }
        if (flag == 0)//内容更新
            goto exit;

        fp = fopen(cfile, "wb+");
        if (fp == NULL)
            return -1;
        sprintf(_version_, "/**\n*This file is automatic generated by bin_tool.exe\n*/\n\n"\
            "int get_revision(void)\n"\
            "{\n"\
            "    return %d;\n"\
            "}\n\n"\
            "const char *get_verstring(void)\n"\
            "{\n"\
            "    return \"%s\";\n"\
            "}\n"\
            , atoi(ver), ver);
        fputs(_version_, fp);
        fclose(fp);
        goto exit;
    }
    else
    {
        memset(&fw_info, 0, sizeof(firmware_info_t));
        fw_info.magic = 0xaeae;
        strcpy((char*)fw_info.version, ver);

        if (opt_fix_time)
        {
            time(&timep);
            p = gmtime(&timep);
            printf("%d\n", p->tm_sec); /*获取当前秒*/
            printf("%d\n", p->tm_min); /*获取当前分*/
            printf("%d\n", 8 + p->tm_hour);/*获取当前时,这里获取西方的时间,刚好相差八个小时*/
            printf("%d\n", p->tm_mday);/*获取当前月份日数,范围是1-31*/
            printf("%d\n", 1 + p->tm_mon);/*获取当前月份,范围是0-11,所以要加1*/
            printf("%d\n", 1900 + p->tm_year);/*获取当前年份,从1900开始，所以要加1900*/
            printf("%d\n", p->tm_yday); /*从今年1月1日算起至今的天数，范围为0-365*/

            sprintf(dest_file_name + strlen(dest_file_name), "_r%s_%d%02d%02d%02d%02d%02d.bin",
                fw_info.version, 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, 8 + p->tm_hour, p->tm_min, p->tm_sec);
        }
        else
        {
            sprintf(dest_file_name + strlen(dest_file_name), "_Update_r%s.bin", fw_info.version);
        }
        printf("\n%s\n%s\n", src_file_name, dest_file_name);
        fp = fopen(src_file_name, "rb");
        if (fp == NULL) {
            printf("%s open fail\r\n", src_file_name);
            return -1;
        }
        fseek(fp, 0L, SEEK_END);
        fw_info.size = ftell(fp);
        printf("bin size:%d %08x\r\n", fw_info.size, fw_info.size);
        fseek(fp, 0L, SEEK_SET);

        int boot_size = 0;
        n = query_argv((char*)"-m", argc, argv);
        if (n != 0 && n + 2 < argc)
        {
            int boot_arg_index = n + 1;
            opt = 2;
            char outfile[130];
            n = query_argv((char*)"-f", argc, argv);
            if (n != 0 && n + 1 < argc)
            {
                sprintf(outfile, "%s_r%s.bin", argv[n+1],ver);
            }
            else
                sprintf(outfile, "fw_boot_app_r%s.bin", ver);
            printf("merge file:%s\r\n", outfile);
            fp1 = fopen(outfile, "wb+");
            if (fp1 == NULL)
                goto exit;

            f_boot = fopen(argv[boot_arg_index], "rb");
            if (f_boot == NULL)
            {
                printf("%s open fail\r\n", argv[boot_arg_index]);
                goto exit;
            }
            printf("%s open success\r\n", argv[boot_arg_index]);
            fseek(f_boot, 0L, SEEK_END);
            boot_size = ftell(f_boot);
            fseek(f_boot, 0L, SEEK_SET);
            while (1)
            {
                c = fgetc(f_boot);
                if (feof(f_boot))
                {
                    break;
                }
                if (fputc(c, fp1) == EOF)
                {
                    printf("file write error!\n");
                    goto exit;
                }
            }
            int app_offset = 0;

            sscanf(argv[boot_arg_index + 1], "%x", &app_offset);

            printf("*%s %d\r\n", argv[boot_arg_index+1], app_offset);
            printf("boot size:%d\r\n", boot_size);
            for (int i = boot_size; i < app_offset; i++)
            {
                if (fputc(0xff, fp1) == EOF)
                {
                    printf("file write error!\n");
                    goto exit;
                }
            }

            while (1)
            {
                c = fgetc(fp);
                if (feof(fp))
                {
                    break;
                }
                if (fputc(c, fp1) == EOF)
                {
                    printf("file write error!\n");
                    goto exit;
                }
            }
            goto exit;
        }
    }
    if(opt == 1)
    {
        unsigned char fw[512 * 1024];
        unsigned char* pt = fw;

        fp1 = fopen(dest_file_name, "wb+");
        if (fp1 == NULL)
            goto exit;
        fseek(fp1, sizeof(firmware_info_t), SEEK_SET);
        while (1)
        {
            c = fgetc(fp);
            if (feof(fp))
            {
                break;
            }
            if (fputc(c, fp1) == EOF)
            {
                printf("file write error!\n");
                goto exit;
            }
            *pt = c;
            pt++;
        }
        fw_info.crc32 = crc32_halfbyte(fw, fw_info.size, 0);

        int i;
        fseek(fp1, 0L, SEEK_SET);
        unsigned char* ch = (unsigned char*)&fw_info;
        for (i = 0; i < sizeof(firmware_info_t); i++)
        {
            if (fputc(ch[i], fp1) == EOF)
            {
                printf("file write error!\n");
                goto exit;
            }
        }
        //printf("%s %s %s\n",__FUNCTION__,__DATE__,__TIME__);

        //system("svn.exe info --show-item revision >version.txt");
    }
exit:
    if (fp != NULL)
    {
        fclose(fp);
    }
    if (fp1 != NULL)
    {
        fclose(fp1);
        if (opt == 1)
        {
            system("del .\\update.bin");
            char cmd[256];
            sprintf(cmd, "copy %s .\\update.bin", dest_file_name);
            printf("%s\r\n", cmd);
            system(cmd);
        }
    }
    if (f_boot != NULL)
        fclose(f_boot);
    //getch();
    return(0);
}